package edu.chl.vrangogym.persistence.impl;

import edu.chl.vrangogym.persistence.AbstractFacade;
import edu.chl.vrangogym.persistence.entities.Booking;
import edu.chl.vrangogym.persistence.entities.Booking_;
import edu.chl.vrangogym.persistence.entities.WorkoutSession;
import edu.chl.vrangogym.persistence.entities.WorkoutSession_;
import edu.chl.vrangogym.persistence.exception.NonexistentEntityException;
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

/**
 * Class for handling modifications on Bookings in the database.
 * 
 * @author Anders and habbbe
 * 
 */
@Stateless
public class BookingFacade extends AbstractFacade<Booking> {

    @PersistenceContext(unitName = "gym_pu")
    private EntityManager em;

    public BookingFacade() {
        super(Booking.class);
    }

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }
    
    /**
     * Retrieves all bookings after the specified date
     * @param startTime Indicates the start date of a booked workoutsession
     * @return A list of Bookings
     */
    public List<Booking> findAll(Date startTime) {
        
        javax.persistence.criteria.CriteriaBuilder cb = em.getCriteriaBuilder();
        javax.persistence.criteria.CriteriaQuery cq = cb.createQuery();

        Root<Booking> booking = cq.from(Booking.class);
        Path<WorkoutSession> ws = booking.get(Booking_.workoutSession);
        
        cq.select(booking).where(cb.greaterThanOrEqualTo(ws.get(WorkoutSession_.startTime), startTime));

        return em.createQuery(cq).getResultList();
    }

    @Override
    public void remove(Booking b) throws NonexistentEntityException {

        super.remove(b);
        /* TODO FOR TESTING PURPOSES ONLY! Should call super(remove).
         * This is due to EntityManager not injecting during unit tests.
         *****************************************************************
        EntityManager em = Persistence.createEntityManagerFactory("test_gym_pu").createEntityManager();
        
        em.getTransaction().begin(); 
        em.remove(em.merge(b));
        em.getTransaction().commit();
        
         *****************************************************************/

        List<Booking> bookingsWithWS = getBookingsForWorkoutSession(b.getWorkoutSession());

        if (bookingsWithWS.isEmpty()) {

            /*****FOR TESTING, REMOVE WHEN DONE******
            em.getTransaction().begin();
             ****************************************/
            em.remove(em.merge(b.getWorkoutSession()));

            /*****FOR TESTING, REMOVE WHEN DONE******
            em.getTransaction().commit();
             ****************************************/
        }
    }
    
    /**
     * Returns a list of bookings that has referenses to the same workout session
     * @param ws the workout session
     * @return a list of bookings that has referenses to the same workout session
     */
    public List<Booking> getBookingsForWorkoutSession(WorkoutSession ws) {
        
        javax.persistence.criteria.CriteriaBuilder cb = em.getCriteriaBuilder();
        javax.persistence.criteria.CriteriaQuery cq = cb.createQuery();

        Root<Booking> booking = cq.from(Booking.class);

        Predicate cond = cb.equal(booking.get(Booking_.workoutSession), ws);

        cq.where(cond);

        List<Booking> resultList = em.createQuery(cq).getResultList();
        
        return resultList;
    }
}
